﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace AAA.Command
{
    public abstract class AbstractCommand : ICommand
    {
        public const int OK = 0;
        public const int NG = 1;
        public const string COMMAND_TYPE = "COMMAND_TYPE";
        public const int BASIC_INSERT = 1;
        public const int BASIC_UPDATE = 2;
        public const int BASIC_DELETE = 4;
        public const int BASIC_QUERY = 8;

        private DataSet _dsReturn;

        private Dictionary<string, string> _dicIdMapping;
        private Dictionary<string, string> _dicResultMapping;

        public AbstractCommand()
        {
            _dicIdMapping = new Dictionary<string, string>();
            _dicResultMapping = new Dictionary<string, string>();
        }

        #region ICommand 成員
        /// <summary>
        /// 將Execute的結果做轉換, 由Source的DataTable Name轉換為Target DataTable Name
        /// </summary>
        /// <param name="strSource">在Command中預設的名稱</param>
        /// <param name="strTarget">在UI中的ID</param>
        public void AddResultMapping(string strSource, string strTarget)
        {
            if (_dicResultMapping.ContainsKey(strSource))
            {
                _dicResultMapping[strSource] = strTarget;
            }
            else
            {
                _dicResultMapping.Add(strSource, strTarget);
            }
        }

        public string GetResultMapping(string strSource)
        {
            return _dicResultMapping.ContainsKey(strSource)
                    ? _dicResultMapping[strSource]
                    : strSource;
        }

        /// <summary>
        /// 將UI的ID轉換成Command中使用的ID
        /// </summary>
        /// <param name="strSource">在UI中的ID名稱</param>
        /// <param name="strTarget">在Command中使用的名稱(即DataAccess中AddCriteria的Check Field)</param>
        public void AddIdMapping(string strSource, string strTarget)
        {
            if (_dicIdMapping.ContainsKey(strSource))
            {
                _dicIdMapping[strSource] = strTarget;
            }
            else
            {
                _dicIdMapping.Add(strSource, strTarget);
            }
        }

        public string GetIdMapping(string strSource)
        {
            return _dicIdMapping.ContainsKey(strSource)
                    ? _dicIdMapping[strSource]
                    : strSource;
        }
        private string _strErrorMessage;

        public string ErrorMessage
        {
            get { return _strErrorMessage; }
            set { _strErrorMessage = value; }
        }

        private string _strResultTarget;

        public string ResultTarget
        {
            get { return _strResultTarget; }
            set { _strResultTarget = value; }
        }

        private string _strReturnCode;

        public string ReturnCode
        {
            get
            {
                return _strReturnCode;
            }
            set
            {
                _strReturnCode = value;
            }
        }

        private object _oReturnValue;

        public object ReturnValue
        {
            get
            {
                return _oReturnValue;
            }
            set
            {
                _oReturnValue = value;
            }
        }

        public virtual int BeforeExecute(DataSet dsData)
        {
            return OK;
        }

        private List<string> _lstParamList;
        public void AddToParamList(string strParam)
        {
            if (_lstParamList == null)
                _lstParamList = new List<string>();
            
            if(_lstParamList.Contains(strParam))
                return;

            _lstParamList.Add(strParam);
        }

        public void SetParamList(string[] strParams)
        {
            _lstParamList = new List<string>();

            foreach (string strParam in strParams)
                AddToParamList(strParam);
        }

        public string[] GetParamList()
        {
            return _lstParamList == null ? new string[0] : _lstParamList.ToArray();
        }

        protected abstract int ExecuteCommand(DataSet dsData);

        protected void AddDataTable(DataTable dtTable)
        {
            AddDataTable(ResultTarget == null ? "Result" : ResultTarget, dtTable);
        }

        protected void AddDataTable(string strTableName, DataTable dtTable)
        {
            if ((_dsReturn == null) || (strTableName == null) || (dtTable == null))
                return;

            strTableName = GetResultMapping(strTableName);

            if (_dsReturn.Tables.Contains(strTableName))
                _dsReturn.Tables.Remove(strTableName);

            dtTable.TableName = strTableName;
            _dsReturn.Tables.Add(dtTable);
        }

        public int Execute(DataSet dsData)
        {
            if (BeforeExecute(dsData) != OK)
            {
                ReturnValue = dsData;
                return NG;
            }

            _dsReturn = new DataSet();
            if (ExecuteCommand(dsData) != OK)
            {
                ReturnValue = dsData;
                return NG;
            }

            if (AfterExecute(dsData) != OK)
            {
                ReturnValue = dsData;
                return NG;
            }

            DataTable dtTable;
            for(int i = dsData.Tables.Count - 1; i >= 0; i--)
            {
                dtTable = dsData.Tables[i];

                if(dtTable.TableName == null)
                    continue;

                dsData.Tables.RemoveAt(i);

                dtTable.TableName = GetResultMapping(dtTable.TableName);

                if (_dsReturn.Tables.Contains(dtTable.TableName) == false)
                    _dsReturn.Tables.Add(dtTable);
            }

            ReturnValue = _dsReturn;
            return OK;
        }

        public virtual int AfterExecute(DataSet dsData)
        {
            return OK;
        }

        #endregion
    }
}
